/* sipparse.h -- Normalisation and parsing of SIP messages.
 *
 * This file is part of 0cpm Firmerware and SIPproxy64.
 * Its origin (and the place to patch) is in the 0cpm Firmerware.
 *
 * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
 *
 * 0cpm Firmerware is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, version 3.
 *
 * 0cpm Firmerware is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
 */


#include <stdbool.h>
#include <stdint.h>

#include <config.h>

#include <0cpm/text.h>


/*
 * These are parser routines that process incoming SIP messages.
 *
 * The first thing to do with a new SIP message is to run the
 * sip_normalise() routine on it.  This may make the message
 * smaller, by wiping away extravagant spaces and so on.  The
 * resulting message may have very long lines, as broken lines
 * are also turned into single long lines.
 *
 * Note on UTF8:
 *
 * Note that UTF8 is not treated special in any way; the new
 * characters introduced are all >= 0x80 and will not match the
 * checks for specific ASCII characters below.  Also note that
 * the SIP standard does not require knowledge of UTF8 in the
 * message handling part of a phone.
 */


/* Normalise a SIP message, as a prerequisite to further parsing:
 *  - Replace combined whitespace by its canonical or simplest form
 *  - Reunite split header lines
 *  - Standardise header capitalisation
 * An explicit pointer to the attachment will follow, if any.
 */
void sip_normalise (textptr_t *sipmsg, textptr_t *attachment);


/* Extract the components from a request's start-line.
 */
bool sip_splitline_request (textptr_t const *sipmsg, textptr_t *method, textptr_t *requri);


/* Extract the components from a response's start-line.
 */
bool sip_splitline_response (textptr_t const *sipmsg, textptr_t *code, textptr_t *descr);


/* Find the next header in a given SIP message.  The result consists
 * of the full name in "Standard-capitalisation" stored in headername,
 * and the contents as a single line without termination stored in
 * headerval.  When called, these values contain the previous header,
 * the one to find the following for.  The application should pickup
 * headers in their order of appearance, and process them accordingly.
 * Return true if the header was found.
 */
bool sip_nextheader (textptr_t const *sipmsg, textptr_t *headername, textptr_t *headerval);


/* Find the first header in a given SIP message.  The result consists
 * of the full name in "Standard-capitalisation" stored in headername,
 * and the contents as a single line without termination stored in
 * headerval.  The application should pickup headers in their order
 * of appearance, and process them accordingly.
 * Return true if the header was found.
 */
bool sip_firstheader (textptr_t const *sipmsg, textptr_t *headername, textptr_t *headerval);


/* Find the previous header in a given SIP message.  The result consists
 * of the full name in "Standard-capitalisation" stored in headername,
 * and the contents as a single line without termination stored in
 * headerval.  When called, these values contain the next header,
 * the one to find the previous for.  The application should pickup
 * headers in their reverse order of appearance, and process them
 * accordingly.
 * Return true if the header was found.
 */
bool sip_prevheader (textptr_t const *sipmsg, textptr_t *headername, textptr_t *headerval);


/* Find the last header in a given SIP message.  The result consists
 * of the full name in "Standard-capitalisation" stored in headername,
 * and the contents as a single line without termination stored in
 * headerval.  The application should pickup headers in their reverse
 * order of appearance, and process them accordingly.
 * Return true if the header was found.
 */
bool sip_lastheader (textptr_t const *sipmsg, textptr_t *headername, textptr_t *headerval);


/* Find the first SIP URI in a header.  The result is stored in uri.
 * The URI is assumed to be enclosed in angular brackets of, if that
 * is not the case, it is assumed to be a list separated by commas,
 * or semicolons.
 * Return true if the URI was found.
 */
bool sip_firsturi_inheader (textptr_t const *siphdr, textptr_t *uri);


/* Find the next SIP URI in a header.  The result is stored in uri.
 * The URI is assumed to be enclosed in angular brackets of, if that
 * is not the case, it is assumed to be a list separated by commas,
 * or semicolons.
 * Return true if the URI was found.
 */
bool sip_nexturi_inheader (textptr_t const *siphdr, textptr_t *uri);


/* Find the first header parameter.  The name of the parameter is stored
 * in parnm, the value in parval.  Return true if the parameter was found.
 */
bool sip_firstparm_inheader (textptr_t const *siphdr, textptr_t *parnm, textptr_t *parval);


/* Find the next header parameter.  The name of the parameter is stored
 * in parnm, the value in parval.  Return true if the parameter was found.
 */
bool sip_nextparm_inheader (textptr_t const *siphdr, textptr_t *parnm, textptr_t *parval);


/* Find the first URI parameter.  The name of the parameter is stored
 * in parnm, the value in parval.  Return true if the parameter was found.
 */
bool sip_firstparm_inuri (textptr_t const *uri, textptr_t *parnm, textptr_t *parval);


/* Find the next URI parameter.  The name of the parameter is stored
 * in parnm, the value in parval.  Return true if the parameter was found.
 */
bool sip_nextparm_inuri (textptr_t const *uri, textptr_t *parnm, textptr_t *parval);


/* Take a SIP URI apart into its constituent components.
 * Parameters are stripped off, but their analysis should
 * be done with the sip_first/nextparm_inuri() functions.
 * Return false if the URI has a bad format.  Note that a
 * SIP URI need not have a user, so check it after this
 * call if you need the username part.
 */
bool sip_components_inuri (textptr_t const *uri,
				textptr_t *proto,
				textptr_t *user,
				textptr_t *pass,
				textptr_t *dom,
				uint16_t *port);


/* Split a Cseq: header into its two parts: a serial number and a method name.
 * Return false (and set NULL string and 0 value) on error.
 */
bool sip_split_cseq (textptr_t const *cseq, uint32_t *serial, textptr_t *mth);


/* Parse a Via: header to extract the transport (usually UDP or TCP) and
 * the host and port.  Parameters can be extracted with the usual methods.
 */
bool sip_components_invia (textptr_t const *via, textptr_t *transport, textptr_t *host, uint16_t *port);


